/*
uart_tx
#(
	.P_CLK_FRE(50),      //clock frequency(Mhz)
	.P_BAUD_RATE(BAUD_RATE), //serial baud rate
	.P_UART_CHECK(1)  //1 odd 2 even
)
uart_tx(
	.i_clk(clk_50M),              //clock input
	.i_rst_n(rst_n),            //asynchronous reset input, low active 
	.i_tx_data(doutb),          //input wire [7 : 0] tx_data;
	.i_tx_data_valid(tx_data_valid),    //input wire tx_data_valid;
	.o_tx_data_ready(tx_data_ready),    //output wire tx_data_ready;
	.o_tx_pin(tx_pin)            //output wire tx_pin
);
*/
module uart_tx
#(
	parameter 		P_CLK_FRE = 50,      //clock frequency(Mhz)
	parameter 		P_BAUD_RATE = 115200, //serial baud rate
	parameter 		P_UART_CHECK = 1 //1 odd 2 even
)
(
	input 			i_clk,              //clock input
	input 			i_rst_n,            //asynchronous reset input, low active 
	input [7:0] 	i_tx_data,          //data to send
	input 			i_tx_data_valid,    //data to be sent is valid
	output 			o_tx_data_ready,    //send ready
	output 			o_tx_pin            //serial data output
);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = P_CLK_FRE * 1000000 / P_BAUD_RATE;
//state machine code
localparam                       S_IDLE       = 0;
localparam                       S_START      = 1;//start bit
localparam                       S_SEND_BYTE  = 2;//data bits
localparam                       S_CHECK      = 3;//check bits
localparam                       S_STOP       = 4;//stop bit
reg[2:0]                         state;
reg[2:0]                         next_state;
reg[15:0]                        r_cycle_cnt; //baud counter
reg[2:0]                         r_bit_cnt;//bit counter
reg[7:0]                         r_tx_data_latch; //latch data to send
reg                              r_tx_pin; //serial data output
reg                              r_tx_data_ready;
reg 							 r_tx_check;	
always@(posedge i_clk or negedge i_rst_n)
begin
	if(i_rst_n == 1'b0)
		state <= S_IDLE;
	else
		state <= next_state;
end

always@(*)
begin
	case(state)
		S_IDLE:
			if(i_tx_data_valid == 1'b1)
				next_state <= S_START;
			else
				next_state <= S_IDLE;
		S_START:
			if(r_cycle_cnt == CYCLE - 1)
				next_state <= S_SEND_BYTE;
			else
				next_state <= S_START;
		S_SEND_BYTE:
			if(r_cycle_cnt == CYCLE - 1  && r_bit_cnt == 3'd7 && P_UART_CHECK == 0)
				next_state <= S_STOP;
			else if(r_cycle_cnt == CYCLE - 1  && r_bit_cnt == 3'd7 && P_UART_CHECK != 0)
				next_state <= S_CHECK;
			else
				next_state <= S_SEND_BYTE;
		S_CHECK:
			if(r_cycle_cnt == CYCLE - 1)
				next_state <= S_STOP;
			else 
				next_state <= S_CHECK;
		S_STOP:
			if(r_cycle_cnt == CYCLE - 1)
				next_state <= S_IDLE;
			else
				next_state <= S_STOP;
		default:
			next_state <= S_IDLE;
	endcase
end

always@(posedge i_clk or negedge i_rst_n)
begin
	if(i_rst_n == 1'b0)
		begin
			r_tx_data_ready <= 1'b0;
		end
	else if(state == S_IDLE)
		if(i_tx_data_valid == 1'b1)
			r_tx_data_ready <= 1'b0;
		else
			r_tx_data_ready <= 1'b1;
	else if(state == S_STOP && r_cycle_cnt == CYCLE - 1)
			r_tx_data_ready <= 1'b1;
end
assign o_tx_data_ready = r_tx_data_ready;

always@(posedge i_clk or negedge i_rst_n)
begin
	if(i_rst_n == 1'b0)
		begin
			r_tx_data_latch <= 8'd0;
		end
	else if(state == S_IDLE && i_tx_data_valid == 1'b1)
			r_tx_data_latch <= i_tx_data;		
end

always@(posedge i_clk or negedge i_rst_n)
begin
	if(i_rst_n == 1'b0)
			r_bit_cnt <= 3'd0;
	else if(state == S_SEND_BYTE)
		if(r_cycle_cnt == CYCLE - 1)
			r_bit_cnt <= r_bit_cnt + 3'd1;
		else
			r_bit_cnt <= r_bit_cnt;
	else
		r_bit_cnt <= 3'd0;
end

always@(posedge i_clk or negedge i_rst_n)
begin
	if(i_rst_n == 1'b0)
		r_cycle_cnt <= 16'd0;
	else if((state == S_SEND_BYTE && r_cycle_cnt == CYCLE - 1) || next_state != state)
		r_cycle_cnt <= 16'd0;
	else
		r_cycle_cnt <= r_cycle_cnt + 16'd1;	
end

always@(posedge i_clk or negedge i_rst_n) 
begin
	if(i_rst_n == 1'b0)
		r_tx_check <= 1'b0;
	else if(state == S_START)
		r_tx_check <= r_tx_data_latch[7] ^ r_tx_data_latch[6] ^ r_tx_data_latch[5] ^ r_tx_data_latch[4] ^ r_tx_data_latch[3] ^ r_tx_data_latch[2] ^ r_tx_data_latch[1] ^ r_tx_data_latch[0];
    else
        r_tx_check <= r_tx_check;
end

always@(posedge i_clk or negedge i_rst_n)
begin
	if(i_rst_n == 1'b0)
		r_tx_pin <= 1'b1;
	else
		case(state)
			S_IDLE,S_STOP:
				r_tx_pin <= 1'b1; 
			S_START:
				r_tx_pin <= 1'b0; 
			S_SEND_BYTE:
				r_tx_pin <= r_tx_data_latch[r_bit_cnt];
			S_CHECK:
				if(P_UART_CHECK == 1)
					r_tx_pin <= ~r_tx_check;	
				else if(P_UART_CHECK == 2)	
					r_tx_pin <= r_tx_check;	
				else
					r_tx_pin <= 1'b1;	
			default:
				r_tx_pin <= 1'b1; 
		endcase
end
assign o_tx_pin = r_tx_pin;

endmodule 